#include "lista.h"
#define MAXLINE 1000
#define TRUEFLAG 't'
#define FALSEFLAG 'f'

/*~~~~~~~~~~~~~~~   PRUEBAS DEL TAD LISTA ENLAZADA    ~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~          Y DE SU ITERADOR           ~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~                                     ~~~~~~~~~~~~~~~*/

//Imprime el nombre del test y su resultado y cambia el valor del
//caracter recibido por parámetro si la prueba dio error.
void print_test(char* name, bool resultado, char* result){

	printf("\t%s: %s\n", name, resultado? "OK" : "ERROR");
	
	if(!resultado) *result=FALSEFLAG;
}

void print_header(char* name){
	
	printf("\n~~~~~%s~~~~~\n",name);

}

//Pruebas de la lista enlazada.
void pruebas_lista(char* result){
	
	//Definición de los elementos que van a ser insertados a la lista.
	char* p1="String1";
	char* p2="String2";
	char* p3="String3";
	
	//Prueba el funcionamiento básico de la lista enlazada.
	print_header("Prueba el funcionamiento básico de la lista enlazada");
	lista_t* l=lista_crear();
	
	print_test("Lista esta vacia",lista_esta_vacia(l),result);
	
	print_test("Insertar primero",lista_insertar_primero(l,p1),result);
	
	print_test("Lista no esta vacia",!lista_esta_vacia(l),result);
	
	print_test("Lista insertar ultimo",lista_insertar_ultimo(l,p2),result);
	
	print_test("Lista ve su primer elemento",lista_ver_primero(l)==p1,result);
	
	print_test("Lista borra primer elemento",lista_borrar_primero(l)==p1,result);
	
	print_test("Elemento siguiente es actual primero",lista_ver_primero(l)==p2,result);
	
	print_test("El largo es el indicado",lista_largo(l)==1,result);
	
	lista_borrar_primero(l);
	
	//Prueba el funcionamiento al insertar muchos elementos al
	//principio y al final de la lista.
	int i;
	for(i=0;i<100000;i++) lista_insertar_primero(l,p3);
	for(i=0;i<100000;i++) lista_insertar_ultimo(l,p3);
	
	print_test("Lista agrega 100 000 elementos al principio yal final",lista_largo(l)==200000,result);
	
	lista_destruir(l,NULL);
	
	//Prueba el funcionamiento de la recepción de la función
	//para destruir datos.
	lista_t* lista_con_heap=lista_crear();
	
	char* heapstr=(char*)malloc(MAXLINE*sizeof(char));
	
	print_test("Lista agrega elemento del heap al final",lista_insertar_primero(lista_con_heap,heapstr),result);
	
	lista_destruir(lista_con_heap,free);

}

void pruebas_entrada_lista(char* result){
	
	//Verificación de la entrada de la lista.
	
	lista_t* list=lista_crear();
	
	print_header("Verificación de la entrada de la lista enlazada");
	
	print_test("Lista nula vacia",!lista_esta_vacia(NULL),result);
	
	print_test("Lista nula insertar primero",!lista_insertar_primero(NULL,"hola"),result);
	
	print_test("Lista nula insertar ultimo",!lista_insertar_ultimo(NULL,"hola"),result);
	
	print_test("Insertar elemento nulo en lista",!lista_insertar_primero(list,NULL),result);
	
	print_test("Lista nula no puede ver su primer elemento",!lista_ver_primero(NULL),result);
	
	print_test("Lista nula no puede borrar su primer elemento",!lista_borrar_primero(NULL),result);
	
	print_test("El largo de la lista nula es 0 por definición",!lista_largo(NULL),result);
	
	lista_destruir(list,NULL);

}

//Pruebas del iterador de la lista enlazada.
void pruebas_iterador(char* result){

	//Definición de los elementos que van a ser insertados a la lista.
	char* s1="String1";
	char* s2="String2";

	//Creación de la lista e inserción de los elementos.
	lista_t* list=lista_crear();
	lista_insertar_ultimo(list, s1);
	lista_insertar_ultimo(list, s2);
	
	//Pruebas de funcionamiento básico del iterador.
	print_header("Prueba el funcionamiento básico del iterador");
	lista_iter_t* iterador=lista_iter_crear(list);
	
	print_test("Iterador ve el actual correcto",lista_iter_ver_actual(iterador)==s1,result);
	
	print_test("Iterador avanza sobre la lista",lista_iter_avanzar(iterador),result);
	
	print_test("Iterador ve el actual correcto",lista_iter_ver_actual(iterador)==s2,result);
	
	lista_iter_avanzar(iterador);
	
	print_test("Iterador esta al final",lista_iter_al_final(iterador),result);
	
	lista_iter_destruir(iterador);
	
	lista_destruir(list,NULL);
	
}

void pruebas_entrada_iterador(char* result){
		
	//Verificación de la entrada del iterador.
	
	print_header("Verificación de la entrada del iterador");
	
	print_test("Crear iterador de la lista nula",!lista_iter_crear(NULL),result);
	
	print_test("Avanzar iterador nulo",!lista_iter_avanzar(NULL),result);
	
	print_test("Ver actual del iterador nulo",!lista_iter_ver_actual(NULL),result);
	
	print_test("Iterador nulo esta al final",!lista_iter_al_final(NULL),result);

}

//Pruebas que combinan a la lista con el iterador.
void pruebas_lista_iterador(char* result){
	
	//Definición de los datos que serán insertados.
	char* s1="String1";
	char* s2="String2";
	char* s3="String3";
	
	//Funcionamiento básico de las funciones combinadas.
	print_header("Prueba el funcionamiento básico de las funciones combinadas");
	lista_t* list=lista_crear();
	
	lista_iter_t* iterador=lista_iter_crear(list);
	
	print_test("Iterador inserta al principio de la lista",lista_insertar(list, iterador, s1),result);
	
	print_test("El primer elemento es el primero elemento insertado",lista_ver_primero(list)==s1,result);
	
	print_test("Iterador avanza sobre la lista",lista_iter_avanzar(iterador),result);

	print_test("Iterador esta al final",lista_iter_al_final(iterador),result);
	
	print_test("Iterador inserta al final",lista_insertar(list, iterador, s2),result);
	
	print_test("El elemento actual del iterador es el que se acaba de ingresar",lista_iter_ver_actual(iterador)==s2,result);
	
	lista_insertar(list, iterador, s3);
	
	lista_borrar(list, iterador);
	
	print_test("Al ingresar y borrar elemento, el actual sigue siendo el mismo",lista_iter_ver_actual(iterador)==s2,result);
	
	print_test("Iterador borra el elemento sobre el cual esta parado",lista_borrar(list, iterador)==s2,result);
	
	print_test("El tamaño de la lista es el adecuado",lista_largo(list)==1,result);
	
	print_test("Iterador esta al final",lista_iter_al_final(iterador),result);
	
	print_test("Iterador no avanza si esta al final",!lista_iter_avanzar(iterador),result);
	
	//Inserción masiva de elementos a la lista por el iterador.	
	int i;
	for(i=0;i<99999;i++) lista_insertar(list, iterador, s2);
	print_test("Insertar 100 000 con iterador", (lista_largo(list)==100000) && (lista_iter_ver_actual(iterador)==s2),result);
	
	for(i=0;i<99999;i++) lista_iter_avanzar(iterador);
	print_test("Iterador esta al final de los 100 000 elementos",lista_iter_al_final(iterador),result);
	
	lista_iter_destruir(iterador);
	
	lista_destruir(list, NULL);
	
}

void pruebas_entrada_combinadas(char* result){
	
	lista_t* list=lista_crear();
	
	lista_iter_t* iterador=lista_iter_crear(list);
		
	//Verificación de la entrada de las funciones combinadas.
	
	print_header("Verificación de la entrada de las funciones combinadas");
	
	print_test("Insertar en lista nula",!lista_insertar(NULL,iterador,"hola"),result);
	
	print_test("Insertar con iterador nulo",!lista_insertar(list,NULL,"hola"),result);
	
	print_test("Insertar dato nulo",!lista_insertar(list,iterador,NULL),result);
	
	print_test("Borrar en lista nula",!lista_borrar(NULL,iterador),result);
	
	print_test("Borrar con iterador nulo",!lista_borrar(list,NULL),result);
	
	lista_destruir(list,NULL);
	
	lista_iter_destruir(iterador);

}

void print_resultado(char* result){
	
	if(*result==TRUEFLAG){
		
		printf("\n**********");
		
		printf("El programa ha pasado todas las pruebas con éxito");
		
		printf("**********\n");
	
	}else if(*result==FALSEFLAG){
		
		printf("\nLas pruebas han encontrado errores en el programa. ");
	
		printf("Verificar su funcionamiento.\n");

	}else printf("\nError en las pruebas.\n");
	
}

//Ejecución de todas las pruebas.
int main(void){
	
	char* result=(char*)malloc(sizeof(char));
	
	//Si el resultado no se altera, las pruebas salieron bien.
	*result=TRUEFLAG;
	
	pruebas_lista(result);
	
	pruebas_entrada_lista(result);
	
	pruebas_iterador(result);
	
	pruebas_entrada_iterador(result);
	
	pruebas_lista_iterador(result);
	
	pruebas_entrada_combinadas(result);
	
	print_resultado(result);
	
	free(result);
	
	return 0;

}
